home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume91 / utilitys / beav_132 / part09 / display.c
C/C++ Source or Header  |  1991-11-14  |  31KB  |  1,347 lines

  1. /*
  2. * The functions in this file handle redisplay. The
  3. * redisplay system knows almost nothing about the editing
  4. * process; the editing functions do, however, set some
  5. * hints to eliminate a lot of the grinding. There is more
  6. * that can be done; the "vtputc" interface is a real
  7. * pig.  The MEMMAP
  8. * changes things around for memory mapped video. With
  9. * both off, the terminal is a VT52.
  10. */
  11.  
  12. #include    <sys/types.h> 
  13. #include    <sys/stat.h> 
  14. #include    "def.h"
  15.  
  16. D32 get_long ();
  17. D16 get_int ();
  18. void writ_echo ();
  19. void uline ();
  20. void ucopy ();
  21. void modeline ();
  22. void bin_to_text ();
  23. uint fill_buf ();
  24. uint get_currow ();
  25. uint get_curcol ();
  26. #if MSDOS
  27. void    mem_line ();
  28. #endif
  29.  
  30. extern    char    MSG_prn_to[];
  31. extern    char    MSG_disp_r_n[];
  32. extern    char    MSG_11lX[];
  33. extern    char    MSG_11lo[];
  34. extern    char    MSG_11ld[];
  35. extern    char    MSG_03o[];
  36. extern    char    MSG_06o[];
  37. extern    char    MSG_011lo[];
  38. extern    char    MSG_03u[];
  39. extern    char    MSG_05u[];
  40. extern    char    MSG_010lu[];
  41. extern    char    MSG_02X[];
  42. extern    char    MSG_04X[];
  43. extern    char    MSG_08lX[];
  44. extern    char    MSG_prog_name[];
  45. extern    char    MSG_disp_b_lst[];
  46. extern    char    MSG_file[];
  47. extern    char    MSG_RO[];
  48. extern    char    MSG_WL[];
  49. extern    char    MSG_RW[];
  50. extern    char    MSG_AU[];
  51. extern    char    MSG_NOT_AU[];
  52. extern    char    MSG_curs_asc[];
  53. extern    char    MSG_curs_ebc[];
  54. extern    char    MSG_curs_hex[];
  55. extern    char    MSG_curs_bin[];
  56. extern    char    MSG_curs_dec[];
  57. extern    char    MSG_curs_oct[];
  58. extern    char    MSG_siz_8[];
  59. extern    char    MSG_siz_16[];
  60. extern    char    MSG_siz_32[];
  61. extern    char    MSG_siz_null[];
  62. extern    char    MSG_int_shift[];
  63. extern    char    MSG_mot_shift[];
  64. extern    char    MSG_print1[];
  65. extern    char    MSG_print2[];
  66. #if RUNCHK
  67. extern    char    ERR_disp_1[];
  68. extern    char    ERR_disp_2[];
  69. extern    char    ERR_disp_3[];
  70. extern    char    ERR_disp_4[];
  71. extern    char    ERR_disp_5[];
  72. extern    char    ERR_disp_6[];
  73. #endif
  74.  
  75. extern char ebcdic_table[];
  76.  
  77. extern  bool    mem_map;
  78.  
  79. /*
  80. * You can change these back to the types
  81. * implied by the name if you get tight for space. If you
  82. * make both of them "int" you get better code on the VAX.
  83. * They do nothing if this is not Gosling redisplay, except
  84. * for change the size of a structure that isn't used.
  85. * A bit of a cheat.
  86. */
  87. #define XCHAR   int
  88. #define XSHORT  int
  89.  
  90. /*
  91. * A video structure always holds
  92. * an array of characters whose length is equal to
  93. * the longest line possible. Only some of this is
  94. * used if "ncol" isn't the same as "NCOL".
  95. */
  96. typedef struct vid
  97. {
  98.     short   v_hash;             /* Hash code, for compares.     */
  99.     short   v_flag;             /* Flag word.                   */
  100.     short   v_color;            /* Color of the line.           */
  101.     XSHORT v_cost;      /* Cost of display.     */
  102.     char    v_text[NCOL];       /* The actual characters.       */
  103. }                   VIDEO;
  104.  
  105. #define VFCHG   0x0001          /* Changed.                     */
  106. #define VFHBAD  0x0002          /* Hash and cost are bad.       */
  107.  
  108. /*
  109. * SCORE structures hold the optimal
  110. * trace trajectory, and the cost of redisplay, when
  111. * the dynamic programming redisplay code is used.
  112. * If no fancy redisplay, this isn't used. The trace index
  113. * fields can be "char", and the score a "short", but
  114. * this makes the code worse on the VAX.
  115. */
  116. typedef struct
  117. {
  118.     XCHAR s_itrace;             /* "i" index for track back.    */
  119.     XCHAR s_jtrace;             /* "j" index for trace back.    */
  120.     XSHORT s_cost;              /* Display cost.                */
  121. }               SCORE;
  122.  
  123. int     sgarbf = TRUE;          /* TRUE if screen is garbage.   */
  124. int     vtrow = 0;              /* Virtual cursor row.          */
  125. int     vtcol = 0;              /* Virtual cursor column.       */
  126. int     tthue = CNONE;          /* Current color.               */
  127. int     ttrow = HUGE;           /* Physical cursor row.         */
  128. int     ttcol = HUGE;           /* Physical cursor column.      */
  129. int     tttop = HUGE;           /* Top of scroll region.        */
  130. int     ttbot = HUGE;           /* Bottom of scroll region.     */
  131. char    file_off_bad = FALSE;   /* Have file offsets been changed */
  132.  
  133. VIDEO * vscreen[NROW];          /* Edge vector, virtual.        */
  134. VIDEO * pscreen[NROW];          /* Edge vector, physical.       */
  135. VIDEO video[2 * (NROW)];        /* Actual screen data.          */
  136. VIDEO blanks;                   /* Blank line image.            */
  137.  
  138. /*
  139. * Initialize the data structures used
  140. * by the display code. The edge vectors used
  141. * to access the screens are set up. The operating
  142. * system's terminal I/O channel is set up. Fill the
  143. * "blanks" array with ASCII blanks. The rest is done
  144. * at compile time. The original window is marked
  145. * as needing full update, and the physical screen
  146. * is marked as garbage, so all the right stuff happens
  147. * on the first call to redisplay.
  148. */
  149. void vtinit ()
  150. {
  151.     register    VIDEO * vp;
  152.     register int    i;
  153.  
  154.     ttopen ();
  155.     ttinit ();
  156.     vp = &video[0];
  157.     for (i = 0; i < NROW; ++i)
  158.     {
  159.         vscreen[i] = vp;
  160.         ++vp;
  161.         pscreen[i] = vp;
  162.         ++vp;
  163.     }
  164.     blanks.v_color = CTEXT;
  165.     for (i = 0; i < NCOL; ++i)
  166.         blanks.v_text[i] = ' ';
  167. }
  168.  
  169. /*
  170. * Tidy up the virtual display system
  171. * in anticipation of a return back to the host
  172. * operating system. Right now all we do is position
  173. * the cursor to the last line, erase the line, and
  174. * close the terminal channel.
  175. */
  176. void vttidy ()
  177. {
  178.     ttcolor (CTEXT);
  179.     ttnowindow ();              /* No scroll window.    */
  180.     ttmove (nrow - 1, 0);       /* Echo line.           */
  181.     tteeol ();
  182.     tttidy ();
  183.     ttflush ();
  184.     ttclose ();
  185. }
  186.  
  187. /*
  188. * Move the virtual cursor to an origin
  189. * 0 spot on the virtual display screen. I could
  190. * store the column as a character pointer to the spot
  191. * on the line, which would make "vtputc" a little bit
  192. * more efficient. No checking for errors.
  193. */
  194. void vtmove (row, col)
  195. {
  196.     vtrow = row;
  197.     vtcol = col;
  198. }
  199.  
  200. /*
  201. * Write a character to the virtual display,
  202. * dealing with long lines and the display of unprintable
  203. * things like control characters. Also expand tabs every 8
  204. * columns. This code only puts printing characters into
  205. * the virtual display image. Special care must be taken when
  206. * expanding tabs. On a screen whose width is not a multiple
  207. * of 8, it is possible for the virtual cursor to hit the
  208. * right margin before the next tab stop is reached. This
  209. * makes the tab code loop if you are not careful.
  210. * Three guesses how we found this.
  211. */
  212. void vtputc (c)
  213. register char   c;
  214. {
  215.     register    VIDEO * vp;
  216.  
  217.     vp = vscreen[vtrow];
  218.     if (vtcol >= ncol)
  219.         vp -> v_text[ncol - 1] = '$';
  220.     else
  221.         if (ISCTRL (c) != FALSE)
  222.         {
  223.             vtputc ('^');
  224.             vtputc (c ^ 0x40);
  225.         }
  226.         else
  227.         {
  228.             vp -> v_text[vtcol] = c;
  229.             vtcol++;
  230.         }
  231.  
  232. }
  233. /*
  234. * Write an entire screen line in the correct format.    pvr
  235. *
  236. * This code only puts printing characters into
  237. * the virtual display image.
  238. * Return TRUE if something was printed to the line.
  239. */
  240. #define REGI  register
  241. bool vtputd (wp, row)
  242. WINDOW * wp;
  243. int     row;                    /* line # to print to v screen */
  244.  
  245. {
  246.     REGI VIDEO * vp;
  247.     REGI char   mode;
  248.     REGI A32    row_offst;
  249.     REGI uint   chrs_per_row,
  250.         lin_offset,
  251.         i,
  252.         chrs_in_lin;
  253.     LINE * cur_line;
  254.     static char w_buf[128];      /* temp buffer for data */
  255.  
  256.     vp = vscreen[vtrow];        /* point to VIDEO structure to print into */
  257.     mode = R_TYPE(wp);          /* get type of format structure */
  258.  
  259.     /* get number of bytes per row */
  260.     chrs_per_row = R_BYTES(wp);
  261.  
  262.     /* determine the offset from begining of the buffer for this line */
  263.     row_offst = WIND_POS(wp) + (row * chrs_per_row);
  264.  
  265.     /* search for and point to first character in buffer to be printed */
  266.     cur_line = wp -> w_linep;   /* start with current first window line */
  267.     while (TRUE)
  268.     {                       /* find line with desired character */
  269.         if (cur_line == wp -> w_bufp -> b_linep)
  270.         {                   /* at end of buffer? */
  271.             return (FALSE);
  272.         }
  273.         if (cur_line -> l_file_offset > row_offst)
  274.         {
  275.             /* if less than current line */
  276.             cur_line = cur_line -> l_bp;/* step back */
  277.         }
  278.         else
  279.             if ((cur_line -> l_file_offset + cur_line -> l_used) <= row_offst)
  280.             {
  281.                 cur_line = cur_line -> l_fp;/* step ahead */
  282.             }
  283.             else
  284.                 break;
  285.     }
  286.  
  287.     lin_offset = row_offst - cur_line -> l_file_offset;/* offset into line */
  288.  
  289.     /* get index into the current line to start reading the current row's data */
  290.     /* copy line text into buffer */
  291.     chrs_in_lin = fill_buf (wp, cur_line, lin_offset, w_buf, chrs_per_row);
  292.  
  293.     /* limit line length to screen width, used in TEXT mode only */
  294.     if (chrs_in_lin > NCOL)
  295.         chrs_in_lin = NCOL;
  296.  
  297.     /* Clear the line to spaces */
  298.     for (i = 0; i < NCOL; i++)
  299.     {
  300.         vp -> v_text[i] = ' ';
  301.     }
  302.     switch (mode)
  303.     {
  304.     case TEXT:
  305.         break;
  306.     case ASCII:
  307.     case EBCDIC:
  308.     case BINARY:
  309.     case HEX:
  310.         /* print the row offset from the start of the file in HEX */
  311.         sprintf (vp -> v_text, MSG_11lX, row_offst);/* to vid buf */
  312.         break;
  313.     case OCTAL:
  314.         /* print the row offset from the start of the file */
  315.         sprintf (vp -> v_text, MSG_11lo, row_offst);/* to vid buf */
  316.         break;
  317.     case DECIMAL:
  318.         /* print the row offset from the start of the file */
  319.         sprintf (vp -> v_text, MSG_11ld, row_offst);/* to vid buf */
  320.         break;
  321. #if RUNCHK
  322.     default:
  323.         writ_echo (ERR_disp_1);
  324.         break;
  325. #endif
  326.     }
  327.  
  328.     /* print the binary data to the text line */
  329.     bin_to_text (w_buf, vp -> v_text, chrs_in_lin,
  330.         wp -> w_fmt_ptr);
  331.  
  332.     vtcol = NCOL;
  333.     return (TRUE);
  334. }
  335.  
  336. /*
  337. *   Print the contents of then binary data buffer bin_buf
  338. *   into the proper mode of text into txt_buf.
  339. *   Process 'len' bytes.
  340. *
  341. *   input:
  342. *           bin_buf     pointer to buffer of binary data to process.
  343. *           txt_buf     pointer to output buffer to print text result into.
  344. *           len         length in bytes of data in bin_buf to process.
  345. *           fmt_ptr     pointer to a ROW_FMT to use to format the data
  346. *                       conversion and printing process.
  347. *   output:
  348. *           none.       
  349. */
  350.  
  351. void bin_to_text (bin_buf, txt_buf, len, fmt_ptr)
  352.  
  353. char   *bin_buf,
  354. *txt_buf;
  355. uint    len;
  356. ROW_FMT *fmt_ptr;
  357.  
  358. {
  359.     uchar   i,
  360.         ch,
  361.         k,
  362.         j,
  363.         mode,
  364.         size,
  365.         *posn;
  366.     uint    temp_int;
  367.     ulong   temp_long;
  368.  
  369.     mode = fmt_ptr -> r_type;   /* get type of format structure */
  370.     size = fmt_ptr -> r_size;   /* get size of format structure */
  371.     posn = fmt_ptr -> r_positions;/* pointer to array of display positions */
  372.  
  373.     switch (mode)
  374.     {
  375.     case TEXT:
  376.     case ASCII:
  377.         for (i = 0; i < len; i++)
  378.         {
  379.             ch = bin_buf[i];
  380.             if ((ch >= ' ') && (ch < 0x7f))
  381.                 txt_buf[posn[0] + i] = ch;
  382.             else
  383.                 txt_buf[posn[0] + i] = '.';
  384.         }
  385.         break;
  386.  
  387.     case EBCDIC:
  388.         for (i = 0; i < len; i++)
  389.         {
  390.             txt_buf[posn[0] + i] =
  391.                 0xff & ebcdic_table[0xff & bin_buf[i]];
  392.         }
  393.         break;
  394.  
  395.     case OCTAL:
  396.         switch (size)
  397.         {
  398.         case BYTES:     /* print octal bytes */
  399.             for (i = 0; i < len; i++)
  400.             {
  401.                 sprintf (&txt_buf[
  402.                                     posn[i]], MSG_03o, 0xff & bin_buf[i]);
  403.             }
  404.             break;
  405.  
  406.         case WORDS:     /* print octal words */
  407.             k = 0;
  408.             for (i = 0; i < len;
  409.                 i += 2)
  410.             {
  411.                 temp_int = get_int (&bin_buf[i]);
  412.                 sprintf (&txt_buf[posn[k++]], MSG_06o, temp_int);
  413.             }
  414.             break;
  415.  
  416.         case DWORDS:    /* print octal double words */
  417.             k = 0;
  418.             for (i = 0; i < len;
  419.                 i += 4)
  420.             {
  421.                 temp_long = get_long (&bin_buf[i]);
  422.                 sprintf (&txt_buf[posn[k++]], MSG_011lo, temp_long);
  423.             }
  424.             break;
  425.         }
  426.         break;
  427.  
  428.     case DECIMAL:
  429.         switch (size)
  430.         {
  431.         case BYTES:     /* print decimal bytes */
  432.             for (i = 0; i < len; i++)
  433.             {
  434.                 sprintf (&txt_buf[
  435.                                     posn[i]], MSG_03u, 0xff & bin_buf[i]);
  436.             }
  437.             break;
  438.  
  439.         case WORDS:     /* print decimal words */
  440.             k = 0;
  441.             for (i = 0; i < len;
  442.                 i += 2)
  443.             {
  444.                 temp_int = get_int (&bin_buf[i]);
  445.                 sprintf (&txt_buf[
  446.                                     posn[k++]], MSG_05u, temp_int);
  447.             }
  448.             break;
  449.  
  450.         case DWORDS:    /* print decimal double words */
  451.             k = 0;
  452.             for (i = 0; i < len; i += 4)
  453.             {
  454.                 temp_long = get_long (&bin_buf[i]);
  455.                 sprintf (&txt_buf[
  456.                                     posn[k++]], MSG_010lu, temp_long);
  457.             }
  458.             break;
  459.         }
  460.         break;
  461.  
  462.     case HEX:
  463.         switch (size)
  464.         {
  465.         case BYTES:     /* print hex bytes and ascii chars */
  466.             for (i = 0; i < len; i++)
  467.             {
  468.                 if ((bin_buf[i] >= ' ') && (bin_buf[i] < 0x7f))
  469.                     txt_buf[posn[i + 16]] = 0xff & bin_buf[i];
  470.                 else
  471.                     txt_buf[posn[i + 16]] = '.';
  472.                 sprintf (&txt_buf[posn[i]], MSG_02X, 0xff & bin_buf[i]);
  473.             }
  474.             break;
  475.  
  476.         case WORDS:     /* print hex words */
  477.             k = 0;
  478.             for (i = 0; i < len; i += 2)
  479.             {
  480.                 temp_int = get_int (&bin_buf[i]);
  481.                 sprintf (&txt_buf[
  482.                                     posn[k++]], MSG_04X, temp_int);
  483.             }
  484.             break;
  485.  
  486.         case DWORDS:    /* print hex double words */
  487.             k = 0;
  488.             for (i = 0; i < len; i += 4)
  489.             {
  490.                 temp_long = get_long (&bin_buf[i]);
  491.                 sprintf (&txt_buf[
  492.                                     posn[k++]], MSG_08lX, temp_long);
  493.             }
  494.             break;
  495.         }
  496.         break;
  497.  
  498.     case BINARY:
  499.         switch (size)
  500.         {
  501.         case BYTES:     /* print binary bits */
  502.             for (i = 0; i < len; i++)
  503.             {
  504.                 ch = bin_buf[i];/* get char to convert */
  505.                 for (k = 0; k < 8; k++)
  506.                 {
  507.                     if (ch & 0x80)
  508.                         txt_buf[posn[i] + k]
  509.                             = '1';
  510.                     else
  511.                         txt_buf[posn[i] + k]
  512.                             = '0';
  513.                     ch = ch << 1;/* slide next bit into place */
  514.                 }
  515.             }
  516.             break;
  517.  
  518.         case WORDS:
  519.             j = 0;
  520.             for (i = 0; i < len; i += 2)
  521.             {
  522.                 temp_int = get_int (&bin_buf[i]);
  523.  
  524.                 for (k = 0; k < 16; k++)
  525.                 {
  526.                     if (temp_int & 0x8000)
  527.                         txt_buf[posn[j] + k]
  528.                             = '1';
  529.                     else
  530.                         txt_buf[posn[j] + k]
  531.                             = '0';
  532.                     temp_int = temp_int << 1;
  533.                     /* slide next bit into place */
  534.                 }
  535.                 j++;
  536.             }
  537.             break;
  538.  
  539.         case DWORDS:
  540.             j = 0;
  541.             for (i = 0; i < len; i += 4)
  542.             {
  543.                 temp_long = get_long (&bin_buf[i]);
  544.                 for (k = 0; k < 32; k++)
  545.                 {
  546.                     if (temp_long & 0x80000000)
  547.                         txt_buf[posn[j] + k]
  548.                             = '1';
  549.                     else
  550.                         txt_buf[posn[j] + k]
  551.                             = '0';
  552.                     temp_long = temp_long << 1;
  553.                     /* slide next bit into place */
  554.                 }
  555.                 j++;
  556.             }
  557.             break;
  558.         }
  559.         break;
  560. #if RUNCHK
  561.     default:
  562.         writ_echo (ERR_disp_2);
  563.         break;
  564. #endif
  565.     }
  566.     len *= (fmt_ptr -> r_chr_per_u + 1);
  567.     /* Clean up any garbage characters left by the sprintf's */
  568.     for (i = 0; i < NCOL; i++)
  569.     {
  570.         if (txt_buf[i] == 0)
  571.             txt_buf[i] = ' ';
  572.     }
  573. }
  574.  
  575. /*
  576. *   Get an int from the buffer.
  577. *   Perform the Intel byte shuffle if necessary
  578. */
  579.  
  580. D16 get_int (w_buf)
  581. uchar  *w_buf;
  582.  
  583. {
  584.     int     temp_int;
  585.  
  586.     if (curwp -> w_intel_mode)
  587.     {
  588.         temp_int = 0xff & w_buf[1];
  589.         temp_int <<= 8;
  590.         temp_int |= 0xff & w_buf[0];
  591.     }
  592.     else
  593.     {
  594.         temp_int = 0xff & w_buf[0];
  595.         temp_int <<= 8;
  596.         temp_int |= 0xff & w_buf[1];
  597.     }
  598.     return (temp_int);
  599. }
  600.  
  601. /*
  602. *   Get an long from the buffer.
  603. *   Perform the Intel byte shuffle if necessary
  604. */
  605.  
  606. D32 get_long (w_buf)
  607. uchar  *w_buf;
  608.  
  609. {
  610.     long    temp_long;
  611.  
  612.     if (curwp -> w_intel_mode)
  613.     {
  614.         temp_long = 0xff & w_buf[3];
  615.         temp_long <<= 8;
  616.         temp_long |= 0xff & w_buf[2];
  617.         temp_long <<= 8;
  618.         temp_long |= 0xff & w_buf[1];
  619.         temp_long <<= 8;
  620.         temp_long |= 0xff & w_buf[0];
  621.     }
  622.     else
  623.     {
  624.         temp_long = 0xff & w_buf[0];
  625.         temp_long <<= 8;
  626.         temp_long |= 0xff & w_buf[1];
  627.         temp_long <<= 8;
  628.         temp_long |= 0xff & w_buf[2];
  629.         temp_long <<= 8;
  630.         temp_long |= 0xff & w_buf[3];
  631.     }
  632.     return (temp_long);
  633. }
  634.  
  635.  
  636. /*
  637. *   Copy a length of bytes from the buffer LINEs into the designated
  638. *   buffer.   If the current LINE does not have enough bytes then
  639. *   advance to the next.   Return the actual number of bytes copied.
  640. *   The number copied would be less than the number requested if
  641. *   end of file is reached.
  642. */
  643.  
  644. uint    fill_buf (wp, lin, lin_off, w_buff, cnt)
  645. WINDOW  *wp;
  646. LINE    *lin;
  647. uint    lin_off,
  648. cnt;
  649. char    *w_buff;
  650. {
  651.     REGI uint   src,
  652.         dest,
  653.         i;
  654.  
  655.     src = lin_off;              /* initialize source line index */
  656.     dest = 0;                   /* initialize destination buffer index */
  657.  
  658.     while (TRUE)
  659.     {
  660.         while (src < lin -> l_used)
  661.         {
  662.             w_buff[dest++] = lin -> l_text[src++];/* copy byte */
  663.  
  664.             if (dest == cnt)
  665.             {               /* if done */
  666.                 return (cnt);   /* then leave */
  667.             }
  668.         }
  669.         if (R_TYPE(wp) == TEXT)
  670.             return (dest);   /* in text mode don't advance to next line */
  671.  
  672.         lin = lin -> l_fp;      /* move to the next line */
  673.         if (lin == wp -> w_bufp -> b_linep)
  674.         {                   /* if past last line */
  675.             {
  676.             for (i = dest; i < cnt; ++i)
  677.                 w_buff[i] = 0;/* fill rest of buffer with zeros */
  678.             return (dest);  /* return number of chars copied */
  679.         }
  680.     }
  681.     src = 0;                /* start next LINE at first byte */
  682. }
  683. return (0);
  684. }
  685.  
  686. /*
  687. * Erase from the end of the
  688. * software cursor to the end of the
  689. * line on which the software cursor is
  690. * located. The display routines will decide
  691. * if a hardware erase to end of line command
  692. * should be used to display this.
  693. */
  694. void vteeol ()
  695. {
  696.     register    VIDEO * vp;
  697.  
  698.     vp = vscreen[vtrow];
  699.     while (vtcol < ncol)
  700.         vp -> v_text[vtcol++] = ' ';
  701. }
  702.  
  703. /*
  704. * Make sure that the display is
  705. * right. This is a three part process. First,
  706. * scan through all of the windows looking for dirty
  707. * ones. Check the framing, and refresh the screen.
  708. * Second, make the
  709. * virtual and physical screens the same.
  710. */
  711. void update ()
  712. {
  713.     register    WINDOW * wp;
  714.     register    VIDEO * vp1;
  715.     register    VIDEO * vp2;
  716.     register uint    i;
  717.     register int    hflag;
  718.  
  719.     hflag = FALSE;              /* Not hard.            */
  720.     wp = wheadp;
  721.     while (wp != NULL)
  722.     {
  723.         /* is this window to be displayed in linked mode */
  724.         if ((curbp -> b_flag & BFLINK) &&
  725.             (wp -> w_bufp == curbp))
  726.         {                   /* move dot to current window's dot position */
  727.             wp -> w_dotp = curwp -> w_dotp;
  728.             wp -> w_doto = curwp -> w_doto;
  729.             move_ptr (wp, 0L, TRUE, TRUE, TRUE); /* insure dot is aligned */
  730.             wind_on_dot (wp);   /* move window to new dot position */
  731.         }
  732.  
  733.         if (wp -> w_flag != 0)
  734.  
  735.         {                   /* Need update.         */
  736.             move_ptr (wp, 0L, FALSE, TRUE, TRUE); /* window on row boundary */
  737.             move_ptr (wp, 0L, TRUE, TRUE, TRUE); /* dot on unit boundary */
  738.             if ((wp -> w_flag & WFFORCE) == 0)
  739.             {
  740.                 wind_on_dot (wp);/* position window on dot */
  741.             }
  742.             i = get_currow (wp); /* Redo this one line, mabey.    */
  743.             if ((wp -> w_flag & ~WFMODE) == WFEDIT)
  744.             {
  745.                 vscreen[i] -> v_color = CTEXT;
  746.                 vscreen[i] -> v_flag |= (VFCHG | VFHBAD);
  747.                 vtmove (i, 0);
  748.                 vtputd (wp, i - wp -> w_toprow);/* print line to the screen */
  749.             }
  750.             else
  751.                 if ((wp -> w_flag & ~WFMODE) == WFMOVE)
  752.                 {
  753.                     while (i < wp -> w_toprow + wp -> w_ntrows)
  754.                     {
  755.                         /* paint entire window */
  756.                         vscreen[i] -> v_color = CTEXT;
  757.                         vscreen[i] -> v_flag |= (VFCHG | VFHBAD);
  758.                         vtmove (i, 0);
  759.                         /* print line to the screen */
  760.                         if (!vtputd (wp, i - wp -> w_toprow))
  761.                             vteeol ();
  762.                         ++i;
  763.                     }
  764.                 }
  765.                 else
  766.                     if ((wp -> w_flag & (WFEDIT | WFHARD)) != 0)
  767.                     {
  768.                         hflag = TRUE;
  769.                         i = wp -> w_toprow;
  770.                         while (i < wp -> w_toprow + wp -> w_ntrows)
  771.                         {
  772.                             /* paint entire window */
  773.                             vscreen[i] -> v_color = CTEXT;
  774.                             vscreen[i] -> v_flag |= (VFCHG | VFHBAD);
  775.                             vtmove (i, 0);
  776.                             /* print line to the screen */
  777.                             if (!vtputd (wp, i - wp -> w_toprow))
  778.                                 vteeol ();
  779.                             ++i;
  780.                         }
  781.                     }
  782.             if ((wp -> w_flag & WFMODE) ||
  783.                 (wp -> w_flag & WFMOVE) ||
  784.                 (wp -> w_flag & WFHARD))
  785.                 modeline (wp);
  786.             wp -> w_flag = 0;
  787.         }
  788.         wp = wp -> w_wndp;
  789.     }
  790.     if (sgarbf != FALSE)
  791.     {                       /* Screen is garbage.   */
  792.         sgarbf = FALSE;         /* Erase-page clears    */
  793.         epresf = FALSE;         /* the message area.    */
  794.         tttop = HUGE;           /* Forget where you set */
  795.         ttbot = HUGE;           /* scroll region.       */
  796.         tthue = CNONE;          /* Color unknown.       */
  797.         ttmove (0, 0);
  798.         tteeop ();
  799. #if MSDOS
  800.         if (mem_map)
  801.         {
  802.             for (i = 0; i < nrow; ++i)
  803.             {
  804.                 mem_line (i, vscreen[i]);
  805.             }
  806.         }
  807.         else
  808.         {
  809. #endif
  810.             for (i = 0; i < nrow; ++i)
  811.             {
  812.                 uline (i, vscreen[i], &blanks);
  813.                 ucopy (vscreen[i], pscreen[i]);
  814.             }
  815. #if MSDOS
  816.         }
  817. #endif
  818.         ttmove (get_currow (curwp), get_curcol (curwp));
  819.         ttflush ();
  820.         return;
  821.     }
  822.     for (i = 0; i < nrow; ++i)
  823.     {                       /* Easy update.         */
  824.         vp1 = vscreen[i];
  825.         vp2 = pscreen[i];
  826.         if ((vp1 -> v_flag & VFCHG) != 0)
  827.         {
  828. #if MSDOS
  829.             if (mem_map)
  830.                 mem_line (i, vp1);
  831.             else
  832. #endif
  833.                 {
  834.                     uline (i, vp1, vp2);
  835.                     ucopy (vp1, vp2);
  836.                 }
  837.         }
  838.     }
  839.     ttmove (get_currow (curwp), get_curcol (curwp));
  840.     ttflush ();
  841. }
  842. /*
  843. *   Get the window relative row in which the cursor will
  844. *   appear. pvr
  845. */
  846. uint    get_currow (wp)
  847. WINDOW * wp;
  848. {
  849.     A32    row;
  850.     /* number of bytes from start of window */
  851.     row = DOT_POS(wp) - WIND_POS(wp);
  852.     /* number of rows down in window */
  853.     row /= R_BYTES(wp);
  854.     row += wp -> w_toprow;
  855. #if RUNCHK
  856.     if (row < wp -> w_toprow)
  857.         printf (ERR_disp_3);
  858.     if (row > (wp -> w_ntrows + wp -> w_toprow))
  859.         printf (ERR_disp_4);
  860. #endif
  861.     return (row & 0xffff);
  862. }
  863.  
  864. /*
  865. *   Get the window relative column in which the cursor will
  866. *   appear. pvr
  867. */
  868. uint    get_curcol (wp)
  869. WINDOW * wp;
  870. {
  871.     long    offset,
  872.     index;
  873.     uint    b_per_u, pos;
  874.  
  875.     b_per_u = R_B_PER_U(wp);
  876.     /* dot offset from start of buffer */
  877.     offset = DOT_POS(wp);
  878.     offset -= wp -> w_disp_shift;
  879.     offset &= ~(b_per_u - 1);
  880.     /* calculate mod of the current file position */
  881.     index = offset & (R_BYTES(wp) - 1);
  882.     index /= b_per_u;
  883.     /* limit to window width */
  884.     if (index >= NCOL)
  885.         index = NCOL;
  886.     pos = wp -> w_fmt_ptr -> r_positions[index] + wp -> w_unit_offset;
  887.     return (pos);
  888. }
  889. #if MSDOS
  890. void    mem_line (row, vvp)
  891. int     row;
  892. VIDEO * vvp;
  893. {
  894.     vvp -> v_flag &= ~VFCHG;    /* Changes done.        */
  895.     ttcolor (vvp -> v_color);
  896.     putline (row + 1, 1, ncol, &vvp -> v_text[0]);
  897. }
  898. #endif
  899. /*
  900. * Update a saved copy of a line,
  901. * kept in a VIDEO structure. The "vvp" is
  902. * the one in the "vscreen". The "pvp" is the one
  903. * in the "pscreen". This is called to make the
  904. * virtual and physical screens the same when
  905. * display has done an update.
  906. */
  907. void ucopy (vvp, pvp)
  908. register    VIDEO * vvp;
  909. register    VIDEO * pvp;
  910. {
  911.     register int    i;
  912.  
  913.     vvp -> v_flag &= ~VFCHG;    /* Changes done.        */
  914.     pvp -> v_flag = vvp -> v_flag;/* Update model.        */
  915.     pvp -> v_hash = vvp -> v_hash;
  916.     pvp -> v_cost = vvp -> v_cost;
  917.     pvp -> v_color = vvp -> v_color;
  918.     for (i = 0; i < ncol; ++i)
  919.         pvp -> v_text[i] = vvp -> v_text[i];
  920. }
  921.  
  922. /*
  923. * Update a single line. This routine only
  924. * uses basic functionality (no insert and delete character,
  925. * but erase to end of line). The "vvp" points at the VIDEO
  926. * structure for the line on the virtual screen, and the "pvp"
  927. * is the same for the physical screen. Avoid erase to end of
  928. * line when updating CMODE color lines, because of the way that
  929. * reverse video works on most terminals.
  930. */
  931. void uline (row, vvp, pvp)
  932. VIDEO * vvp;
  933. VIDEO * pvp;
  934. {
  935.     register char  *cp1;
  936.     register char  *cp2;
  937.     register char  *cp3;
  938.     register char  *cp4;
  939.     register char  *cp5;
  940.     register int    nbflag;
  941.  
  942.     if (vvp -> v_color != pvp -> v_color)
  943.     {                       /* Wrong color, do a    */
  944.         ttmove (row, 0);        /* full redraw.         */
  945.         ttcolor (vvp -> v_color);
  946.         cp1 = &vvp -> v_text[0];
  947.         cp2 = &vvp -> v_text[ncol];
  948.         while (cp1 != cp2)
  949.         {
  950.             ttputc (*cp1++);
  951.             ++ttcol;
  952.         }
  953.         return;
  954.     }
  955.     cp1 = &vvp -> v_text[0];    /* Compute left match.  */
  956.     cp2 = &pvp -> v_text[0];
  957.     while (cp1 != &vvp -> v_text[ncol] && cp1[0] == cp2[0])
  958.     {
  959.         ++cp1;
  960.         ++cp2;
  961.     }
  962.     if (cp1 == &vvp -> v_text[ncol])/* All equal.           */
  963.         return;
  964.     nbflag = FALSE;
  965.     cp3 = &vvp -> v_text[ncol]; /* Compute right match. */
  966.     cp4 = &pvp -> v_text[ncol];
  967.     while (cp3[-1] == cp4[-1])
  968.     {
  969.         --cp3;
  970.         --cp4;
  971.         if (cp3[0] != ' ')      /* Note non-blanks in   */
  972.             nbflag = TRUE;      /* the right match.     */
  973.     }
  974.     cp5 = cp3;                  /* Is erase good?       */
  975.     if (nbflag == FALSE && vvp -> v_color == CTEXT)
  976.     {
  977.         while (cp5 != cp1 && cp5[-1] == ' ')
  978.             --cp5;
  979.         /* Alcyon hack */
  980.         if ((int) (cp3 - cp5) <= tceeol)
  981.             cp5 = cp3;
  982.     }
  983.     /* Alcyon hack */
  984.     ttmove (row, (int) (cp1 - &vvp -> v_text[0]));
  985.     ttcolor (vvp -> v_color);
  986.     while (cp1 != cp5)
  987.     {
  988.         ttputc (*cp1++);
  989.         ++ttcol;
  990.     }
  991.     if (cp5 != cp3)             /* Do erase.            */
  992.         tteeol ();
  993. }
  994.  
  995. /*
  996. * Redisplay the mode line for
  997. * the window pointed to by the "wp".
  998. * This is the only routine that has any idea
  999. * of how the modeline is formatted. You can
  1000. * change the modeline format by hacking at
  1001. * this routine. Called by "update" any time
  1002. * there is a dirty window.
  1003. */
  1004.  
  1005. void modeline (wp)
  1006. register    WINDOW * wp;
  1007. {
  1008.     register char  *cp,
  1009.     mode,
  1010.     size,
  1011.     u_posn,
  1012.     *s;
  1013.     register char   c;
  1014.     register int    n;
  1015.     register    BUFFER * bp;
  1016.     register    A32 posn;
  1017.  
  1018.     static char posn_buf[30] =
  1019.     {
  1020.         0
  1021.     };                          /* krw */
  1022.  
  1023.     mode = wp -> w_fmt_ptr -> r_type;/* get type of format structure */
  1024.     size = wp -> w_fmt_ptr -> r_size;/* get size of format structure */
  1025.  
  1026.     n = wp -> w_toprow + wp -> w_ntrows;/* Location.            */
  1027.     vscreen[n] -> v_color = CMODE;/* Mode line color.     */
  1028.     vscreen[n] -> v_flag |= (VFCHG | VFHBAD);/* Recompute, display.  */
  1029.     vtmove (n, 0);              /* Seek to right line.  */
  1030.     bp = wp -> w_bufp;
  1031.  
  1032.     cp = MSG_prog_name;               /* Program name.  pvr    */
  1033.     n = 5;
  1034.     while ((c = *cp++) != 0)
  1035.     {
  1036.         vtputc (c);
  1037.         ++n;
  1038.     }
  1039.  
  1040.     if ((bp -> b_flag & BFBAD) != 0)/* "?" if trashed.      */
  1041.         vtputc ('?');
  1042.     else
  1043.         vtputc (' ');
  1044.  
  1045.     if ((bp -> b_flag & BFCHG) != 0)/* "*" if changed.      */
  1046.         vtputc ('*');
  1047.     else
  1048.         vtputc (' ');
  1049.  
  1050.     if (insert_mode)            /* "I" if insert mode  */
  1051.         vtputc ('I');
  1052.     else
  1053.         vtputc ('O');
  1054.  
  1055.     if (bp == blistp)
  1056.     {                       /* special list */
  1057.         cp = MSG_disp_b_lst;
  1058.         while ((c = *cp++) != 0)
  1059.         {
  1060.             vtputc (c);
  1061.             ++n;
  1062.         }
  1063.         goto pad;
  1064.     }
  1065.  
  1066.     /* Buffer name */
  1067.     vtputc (' ');
  1068.     ++n;
  1069.     cp = &bp -> b_bname[0];
  1070.     while ((c = *cp++) != 0)
  1071.     {
  1072.         vtputc (c);
  1073.         ++n;
  1074.     }
  1075.     while ((int) (cp - &bp -> b_bname[0]) < NBUFN)
  1076.     {
  1077.         vtputc (' ');
  1078.         n++;
  1079.         cp++;
  1080.     }
  1081.  
  1082.     /* File name.           */
  1083.     vtputc (' ');
  1084.     ++n;
  1085.     cp = MSG_file;
  1086.     while ((c = *cp++) != 0)
  1087.     {
  1088.         vtputc (c);
  1089.         ++n;
  1090.     }
  1091.     cp = &bp -> b_fname[0];
  1092.     while ((c = *cp++) != 0)
  1093.     {
  1094.         vtputc (c);
  1095.         ++n;
  1096.     }
  1097.     cp--;
  1098.     while ((int) (cp - &bp -> b_fname[0]) < NFILE)
  1099.     {
  1100.         vtputc (' ');
  1101.         n++;
  1102.         cp++;
  1103.     }
  1104.  
  1105.     if (bp -> b_flag & BFVIEW)
  1106.         s = MSG_RO;
  1107.     else if (bp -> b_flag & BFSLOCK)
  1108.         s = MSG_WL;
  1109.     else
  1110.         s = MSG_RW;
  1111.  
  1112.     while (*s)
  1113.     {                       /* krw */
  1114.         vtputc (*s++);
  1115.         ++n;
  1116.     }
  1117.  
  1118.     if (auto_update && !(bp -> b_flag & BFVIEW) && bp -> b_bname[0])/* jam */
  1119.         s = MSG_AU;
  1120.     else
  1121.         s = MSG_NOT_AU;
  1122.     for (; *s && n < NCOL;)
  1123.     {
  1124.         vtputc (*s++);
  1125.         ++n;
  1126.     }
  1127.  
  1128.     /* Insert current dot position into mode line. */
  1129.     posn = DOT_POS(wp);
  1130.     u_posn = R_CHR_PER_U(wp) - wp -> w_unit_offset - 1;
  1131.     if (u_posn < 0)
  1132.         u_posn = 0;
  1133.     switch (mode)
  1134.     {
  1135.     case TEXT:
  1136.     case ASCII:
  1137.         sprintf (posn_buf, MSG_curs_asc, posn);
  1138.         break;
  1139.     case EBCDIC:
  1140.         sprintf (posn_buf, MSG_curs_ebc, posn);
  1141.         break;
  1142.     case HEX:
  1143.         sprintf (posn_buf, MSG_curs_hex, posn, u_posn);
  1144.         break;
  1145.     case BINARY:
  1146.         sprintf (posn_buf, MSG_curs_bin, posn, u_posn);
  1147.         break;
  1148.     case DECIMAL:
  1149.         sprintf (posn_buf, MSG_curs_dec, posn, u_posn);
  1150.         break;
  1151.     case OCTAL:
  1152.         sprintf (posn_buf, MSG_curs_oct, posn, u_posn);
  1153.         break;
  1154. #if RUNCHK
  1155.     default:
  1156.         writ_echo (ERR_disp_5);
  1157.         break;
  1158. #endif
  1159.     }
  1160.  
  1161.     cp = posn_buf;
  1162.     while ((c = *cp++) != 0)
  1163.     {
  1164.         vtputc (c);
  1165.         ++n;
  1166.     }
  1167.  
  1168.  
  1169.     if ((mode == HEX) ||
  1170.         (mode == DECIMAL) ||
  1171.         (mode == OCTAL))
  1172.     {
  1173.         switch (size)
  1174.         {
  1175.         case BYTES:
  1176.             sprintf (posn_buf, MSG_siz_8);
  1177.             break;
  1178.         case WORDS:
  1179.             sprintf (posn_buf, MSG_siz_16);
  1180.             break;
  1181.         case DWORDS:
  1182.             sprintf (posn_buf, MSG_siz_32);
  1183.             break;
  1184. #if RUNCHK
  1185.         default:
  1186.             writ_echo (ERR_disp_6);
  1187.             break;
  1188. #endif
  1189.         }
  1190.     }
  1191.     else
  1192.         sprintf (posn_buf, MSG_siz_null);
  1193.  
  1194.     cp = posn_buf;
  1195.     while ((c = *cp++) != 0)
  1196.     {
  1197.         vtputc (c);
  1198.         ++n;
  1199.     }
  1200.  
  1201.     if (wp -> w_intel_mode)
  1202.         sprintf (posn_buf, MSG_int_shift, wp -> w_disp_shift);
  1203.     else
  1204.         sprintf (posn_buf, MSG_mot_shift, wp -> w_disp_shift);
  1205.     cp = posn_buf;
  1206.     while ((c = *cp++) != 0)
  1207.     {
  1208.         vtputc (c);
  1209.         ++n;
  1210.     }
  1211.  
  1212.  
  1213.     /* pad out */
  1214. pad:
  1215.     while (n < ncol)
  1216.     {
  1217.         vtputc (' ');
  1218.         ++n;
  1219.     }
  1220. }
  1221.  
  1222. /*
  1223. * write text to the echo line 
  1224. */
  1225. void    writ_echo (buf)
  1226. char    *buf;
  1227. {
  1228.     int     i;
  1229.     char    *vpp;
  1230.     bool    fill_spac;
  1231.  
  1232.     fill_spac = FALSE;
  1233.     vpp = vscreen[nrow - 1] -> v_text;
  1234.     vscreen[nrow - 1] -> v_color = CTEXT;
  1235.     vscreen[nrow - 1] -> v_flag |= VFCHG;
  1236.     epresf = TRUE;
  1237.  
  1238.     for (i = 0; i < NCOL; i++)
  1239.     {
  1240.         if (buf[i] == 0)
  1241.             fill_spac = TRUE;
  1242.         if (fill_spac)
  1243.             vpp[i] = ' ';
  1244.         else 
  1245.             vpp[i] = buf[i];
  1246.     }
  1247. #if MSDOS
  1248.     if (mem_map)
  1249.     {
  1250.         mem_line (nrow - 1, vscreen[nrow - 1]);
  1251.     }
  1252.     else
  1253. #endif
  1254.         {
  1255.             uline (nrow - 1, vscreen[nrow - 1], pscreen[nrow - 1]);
  1256.             uline (nrow - 1, vscreen[nrow - 1], &blanks);
  1257.             ucopy (vscreen[nrow - 1], pscreen[nrow - 1]);
  1258.             ttflush ();
  1259.         }
  1260. }
  1261.  
  1262. /*
  1263. * Print the current buffer from mark to dot using the 
  1264. * current window's display format.
  1265. * Prompt for file name or io device to print to.
  1266. */
  1267.  
  1268. bool    print ()
  1269. {
  1270.     LINE    *dot_l_sav, *mark_l_sav, *wind_l_sav;
  1271.     int     dot_off_sav, mark_off_sav, wind_off_sav, i;
  1272.     char   s;
  1273.     char    fname[NFILEN];
  1274.     register int    nline;
  1275.     char    buf[NFILEN], buf1[NFILEN];
  1276.  
  1277.     /* save the original window state */
  1278.     dot_l_sav = curwp -> w_dotp;
  1279.     dot_off_sav = curwp -> w_doto;
  1280.     mark_l_sav = curwp -> w_markp;
  1281.     mark_off_sav = curwp -> w_marko;
  1282.     wind_l_sav = curwp -> w_linep;
  1283.     wind_off_sav = curwp -> w_loff;
  1284.  
  1285.     /* if mark is not set then set it to location zero */
  1286.     if (curwp -> w_markp == NULL)
  1287.     {
  1288.         curwp -> w_markp = curwp -> w_bufp -> b_linep -> l_fp;
  1289.         curwp -> w_marko = 0;
  1290.     }
  1291.  
  1292.     nline = 0;
  1293.     if ((s = ereply (MSG_prn_to, fname, NFILEN, NULL)) == ABORT)
  1294.         return (s);
  1295.     adjustcase (fname);
  1296.     if ((s = ffwopen (fname, S_IREAD | S_IWRITE)) != FIOSUC)/* Open writes message. */
  1297.         return (FALSE);
  1298.  
  1299.     sprintf (buf, MSG_print1, fname);
  1300.     writ_echo (buf);
  1301.     /* make dot before mark */
  1302.     if (DOT_POS(curwp) > MARK_POS(curwp))
  1303.         swapmark ();    /* make mark first */
  1304.  
  1305.     while (DOT_POS(curwp) <= MARK_POS(curwp))
  1306.     {
  1307.         /* check if we should quit */
  1308.         if (ttkeyready ())
  1309.         {
  1310.             if (ttgetc () == CTL_G)   /* quit if abort was hit */
  1311.                 break;
  1312.         }
  1313.         nline++;
  1314.         /* move window so that first line is on dot */
  1315.         move_ptr (curwp, DOT_POS(curwp), FALSE, TRUE, FALSE);
  1316.  
  1317.         if (vtputd (curwp, 0))   /* print line into video buffer */
  1318.         {
  1319.             for (i = NCOL; (vscreen[vtrow] -> v_text[i] < '!') ||
  1320.                 (vscreen[vtrow] -> v_text[i] > '~'); i--)
  1321.                 ;
  1322.             i++;
  1323.             if ((s = ffputline (vscreen[vtrow] -> v_text, i)) != FIOSUC)
  1324.                 break;
  1325.             if ((s = ffputline (MSG_disp_r_n, 2)) != FIOSUC)
  1326.                 break;
  1327.         }
  1328.         else
  1329.             break;
  1330.         forwline (0, 1, KRANDOM);   /* advance to next line */
  1331.     }
  1332.     ffclose ();
  1333.     sprintf (buf1, MSG_print2, R_POS_FMT(curwp));
  1334.     sprintf (buf, buf1, (long) nline);
  1335.     writ_echo (buf);
  1336.  
  1337.     /* restore the original window state */
  1338.     curwp -> w_dotp = dot_l_sav;
  1339.     curwp -> w_doto = dot_off_sav;
  1340.     curwp -> w_markp = mark_l_sav;
  1341.     curwp -> w_marko = mark_off_sav;
  1342.     curwp -> w_linep = wind_l_sav;
  1343.     curwp -> w_loff = wind_off_sav;
  1344.     curwp -> w_flag |= WFHARD;  /* insure that window is still presentable */
  1345.     return (TRUE);
  1346. }
  1347.